/**
 * 描述: 业务逻辑处理 - 单词接口
 * 作者: wz
 * 日期: 2023-12-25
*/


const { querySql, downloadFile, waitFor } = require('../utils/index');
const { getWordPronunciation } = require('./common');
const boom = require('boom');
const { body, validationResult } = require('express-validator');
const { 
  CODE_ERROR,
  CODE_SUCCESS, 
} = require('../utils/constant');
const fs = require('fs');
const path = require('path');

// 查询所有单词包列表
async function getWordList(req, res, next) {
  const err = validationResult(req);
  // 如果验证错误，empty不为空
  if (!err.isEmpty()) {
    // 获取错误信息
    const [{ msg }] = err.errors;
    // 抛出错误，交给我们自定义的统一异常处理程序进行错误返回 
    next(boom.badRequest(msg));
  } else {

    let { book_id, user_id } = req.body;
    if( !book_id){
      book_id = 0;
    }
    let query = 'select id,name,words from sys_unit where book_id=' + book_id;
    try{
      let data = await querySql(query)
    	// console.log('任务列表查询===', data);
      if (!data || data.length === 0) {
        res.json({ 
        	code: CODE_SUCCESS, 
        	msg: '暂无数据', 
        	data: null 
        })
      } else {
        // 计算数据总条数
        let studyWords = [];
        if(user_id){
          studyWords = await getStudyWord(user_id, book_id, false);
        } 
        res.json({ 
          code: CODE_SUCCESS, 
          msg: '查询数据成功', 
          data: {
            rows: data,
            studyWords,
          } 
        })
      }
    }catch( err){
      res.json({ 
        code: CODE_ERROR, 
        msg: '暂无数据', 
        data: err 
      })
    }
  }
}

// 添加词汇包
async function addStudyWord(req, res, next) {
  const err = validationResult(req);
  if (!err.isEmpty()) {
    const [{ msg }] = err.errors;
    next(boom.badRequest(msg));
  } else {
    let { words, user_id, book_id, words_known} = req.body;
    if( !words_known){
      words_known = '';
    }

    const query = `insert into sys_studyword(user_id, book_id, words, words_known) values('${user_id}', '${book_id}', '${words}', '${words_known}')`;
    //console.log(query)
    try{  
      let data = await querySql(query);
      //console.log('添加任务===', data);
      if (!data || data.affectedRows === 0) {
        res.json({ 
          code: CODE_ERROR, 
          msg: '添加数据失败', 
          data: null 
        })
      } else {
        // console.log('更新用户余额===', data1);
        res.json({ 
          code: CODE_SUCCESS, 
          msg: '添加数据成功', 
          data
        })
      }
    }catch( err){
      res.json({ 
        code: CODE_ERROR, 
        msg: '添加数据失败', 
        data: err 
      })
    }
  }
}

// 计算两个时间相差多少天
function daysBetweenDates(date1, date2) {
  // 将两个日期都设置为当天的开始时间（午夜）
  const startOfDay1 = new Date(date1);
  startOfDay1.setHours(0, 0, 0, 0);
  let startOfDay2 = new Date();
  if(date2){
    startOfDay2 = new Date(date2);
  }
  startOfDay2.setHours(0, 0, 0, 0);
  // 计算时间差
  const diffTime = startOfDay2 - startOfDay1;
  // 将毫秒差转换为天数
  const diffDays = Math.floor(diffTime / (1000 * 3600 * 24));
  return diffDays;
}

// 查询所有单词包列表
async function getStudyWordList(req, res, next) {
  const err = validationResult(req);
  // 如果验证错误，empty不为空
  if (!err.isEmpty()) {
    // 获取错误信息
    const [{ msg }] = err.errors;
    // 抛出错误，交给我们自定义的统一异常处理程序进行错误返回 
    next(boom.badRequest(msg));
  } else {

    let { book_id, user_id, isEveryday=false } = req.body;
    try{
      let data = await getStudyWord(user_id, book_id, true);
    	// console.log('任务列表查询===', data);
      if (!data || data.length === 0) {
        res.json({ 
        	code: CODE_SUCCESS, 
        	msg: '暂无数据', 
        	data: null 
        })
      } else {
        // 计算数据总条数
        let studyIds = [];
        data.forEach(item => {studyIds.push(item.id)});
        let query = `select study_id,gmt_create from sys_studylog where study_id in (${studyIds.join(',')})`;
        query += ' order by gmt_create';
        let studyLog = await querySql(query);
        // console.log('任务列表查询===', studyLog);
        const DAYS = [ 1, 2, 3, 5, 7, 9, 13, 15, 17, 21, 60, 180];
        for(let i=data.length-1; i>=0; i--){
          let item = data[i];
          let logs = studyLog.filter(item1 => { return item1.study_id == item.id });  
          //console.log(logs)
          item.isTodayStudy = false;
          if( logs.length > 0){
            let lastItem = logs[logs.length-1];
            let lastStudyDay = daysBetweenDates(lastItem.gmt_create, null);
            //console.log('lastStudyDay', lastStudyDay)
            if(lastStudyDay <= 0){
              item.isTodayStudy = true;
            }else if( isEveryday){
              let dayIndex = 0;
              let lastCheckTime = item.gmt_create;
              for( let index=0; index<logs.length; index++){
                let item1 = logs[index];
                let intervalDay = DAYS[0];
                if( dayIndex > 0){
                  if(dayIndex < DAYS.length){
                    intervalDay = DAYS[dayIndex] - DAYS[dayIndex-1];
                  }else{
                    intervalDay = DAYS[DAYS.length-1];
                  }
                }
                let studyDay = daysBetweenDates(lastCheckTime, item1.gmt_create);
                if( studyDay >= intervalDay){
                  dayIndex++;
                  lastCheckTime = item1.gmt_create;
                }
              }
              //console.log('dayIndex', dayIndex)
              if( dayIndex >= DAYS.length){
                item.isTodayStudy = true;
              }else{
                let intervalDay = DAYS[0];
                if(dayIndex > 0){
                  intervalDay = DAYS[dayIndex] - DAYS[dayIndex-1];
                }
                let lastStudyDay = daysBetweenDates(lastCheckTime, null);
                if( lastStudyDay < intervalDay){
                  item.isTodayStudy = true;
                }
              }
            }
            if( isEveryday && item.isTodayStudy){
              // 今天已学习或者还没到复习时间删掉
              data.splice(i, 1);
            }
          }
        }

        res.json({ 
          code: CODE_SUCCESS, 
          msg: '查询数据成功', 
          data: {
            rows: data,
          } 
        })
      }
    }catch( err){
      console.log(err)
      res.json({ 
        code: CODE_ERROR, 
        msg: '暂无数据', 
        data: err 
      })
    }
  }
}

// 查询所有单词包列表
// date_type: 0 不限制 1 最近一个星期 2 最近一个月 3 最近三个月
async function getStudyWord(user_id, book_id, bGetBook, date_type) {
  let query = 'select d.id,book_id,words,words_known,d.gmt_create';
  if(bGetBook){
    query += ',name,image ';
  }
  query += ' from sys_studyword d'
  if(bGetBook){
    query += ' left join sys_book b on d.book_id=b.id';
  }

  let params = ' where book_id>0';   // 不显示手动生词本记录
  if(book_id){
    params += ' and book_id=' + book_id;
  }
  if(user_id){
    params += ' and user_id=' + user_id;
  }
  if(date_type == 1){
    params += ' and gmt_create > DATE_SUB(CURDATE(), INTERVAL 7 DAY)';
  }else if(date_type == 2){
    params += ' and gmt_create > DATE_SUB(CURDATE(), INTERVAL 30 DAY)';
  }else if(date_type == 3){
    params += ' and gmt_create > DATE_SUB(CURDATE(), INTERVAL 90 DAY)';
  }
  if(bGetBook){
    params += ' order by d.gmt_create desc';
  }
  //console.log(query + params)
  let data = await querySql(query + params)
  return data;
}

// 添加学习记录
async function addStudyLog(req, res, next) {
  const err = validationResult(req);
  if (!err.isEmpty()) {
    const [{ msg }] = err.errors;
    next(boom.badRequest(msg));
  } else {
    let { study_id=0, master_id=0, user_id=0, book_id=0, no_counts=[]} = req.body;
    // console.log(req.body);
    try{
      let insertStr = [];
      if( study_id > 0){
        let no_count = 0;
        let findItem = no_counts.find(item=>item.study_id==study_id);
        console.log(findItem);
        if( findItem){
          no_count = findItem.count;
        }
        insertStr.push( `('${study_id}', '${master_id}', '${no_count}')`);
      }else if( book_id>0){
        let data = await getStudyWord(user_id, book_id);
        for( let itemData of data){
          let no_count = 0;
          let findItem = no_counts.find(item=>item.study_id==itemData.id);
          if( findItem){
            no_count = findItem.count;
          }
          insertStr.push( `('${itemData.id}', '${master_id}', '${no_count}')`);
        }
      }
      if( insertStr.length > 0){
        const query = `insert into sys_studylog(study_id,master_id,no_count) values ${insertStr.join(',')}`;
        data = await querySql(query);
        if (!data || data.affectedRows === 0) {
          res.json({ 
            code: CODE_ERROR, 
            msg: '添加数据成功', 
            data
          })
        }else{
          res.json({ 
            code: CODE_SUCCESS, 
            msg: '添加数据失败', 
            data: null 
          })
        }
      }else{
        res.json({ 
          code: CODE_ERROR, 
          msg: '未找到学习记录', 
          data: null 
        })
      }
    }catch( err){
      res.json({ 
        code: CODE_ERROR, 
        msg: '添加数据失败', 
        data: err 
      })
    }
  }
}

function getRandomUniqueElements(arr, count) {
  // 如果数组长度小于请求的数量，直接返回
  if (arr.length <= count) {
    return arr;
  }
  // 创建一个空集合用于存储不重复的元素
  let uniqueElements = new Set();

  // 当集合中的元素数量小于指定数量时，继续循环
  while (uniqueElements.size < count) {
    // 生成一个随机索引
    const randomIndex = Math.floor(Math.random() * arr.length);

    // 将随机选中的元素添加到集合中
    uniqueElements.add(arr[randomIndex]);
  }

  // 将Set转换回数组
  return Array.from(uniqueElements);
}

// 查询测试列表
async function getExamList(req, res, next) {
  const err = validationResult(req);
  // 如果验证错误，empty不为空
  if (!err.isEmpty()) {
    // 获取错误信息
    const [{ msg }] = err.errors;
    // 抛出错误，交给我们自定义的统一异常处理程序进行错误返回 
    next(boom.badRequest(msg));
  } else {

    let { book_id, user_id, study_id, date_type } = req.body;
    
    try{
      let ret = [];
      let allWords = await querySql('select word,word_zh from sys_allword');
      if( allWords){
        let examWords = [];
        let randomZhCount = 3;
        if( user_id){
          let data = await getStudyWord(user_id, book_id, false, date_type);
          if(data){
            for(let i of data){
              if( !study_id || i.id == study_id ){
                let words = i.words.split(',');
                for(let word of words){
                  let findItem = allWords.find(item => item.word === word);
                  if(findItem){
                    findItem.book_id = i.book_id;
                    examWords.push(findItem);
                  }
                }
              }
            }
          }
        }else{
          // 从所有单词表里随机50个
          examWords = getRandomUniqueElements(allWords, 50);
          randomZhCount = 7;
        }
        for(let i of examWords){
          let randomZh = getRandomUniqueElements(allWords, randomZhCount);
          i.randomZh = [];
          for(let j of randomZh){
            i.randomZh.push(j.word_zh);
          }
          ret.push(i);
        }
      }
      res.json({ 
        code: CODE_SUCCESS, 
        msg: '查询数据成功', 
        data: {
          rows: ret,
        } 
      })
    }catch( err){
      console.log(err)
      res.json({ 
        code: CODE_ERROR, 
        msg: '暂无数据', 
        data: err 
      })
    }
  }
}




// 定时获取单词发音
async function onTimerWordVoice() {

  
  let words = await querySql('select word,phonetic,word_zh from sys_allword');
  if(words){
    let count = 0;
    for( let i of words ){
      let filename = path.join(__dirname, '../public/upload/voice/', i.word + '.mp3');
      let word_valid = i.word.replace(/[’]/g, '\'');
      let bWait = false;
      try{  
        if(!fs.existsSync(filename)){
          // 下载发音文件y
          let url = 'https://sensearch.baidu.com/gettts?lan=uk&spd=3&source=alading&text=' + encodeURIComponent(word_valid);
          await downloadFile(url, filename);
          bWait = true;
        }
        if(!i.phonetic || !i.word_zh){
          let words = word_valid.split(' ');
          let phonetic = '/';
          let word_zh = '';
          for( let word of words){
            if(word.length <= 0){
              continue;
            }
            let ret = await getWordPronunciation(word);
            if(ret.phonetic.length > 0){
              if( ret.phonetic.startsWith('/') && ret.phonetic.endsWith('/')){
                phonetic += ret.phonetic.substring(1, ret.phonetic.length - 1);
              }else{
                phonetic += ret;
              }
            }else{
              console.log('获取单词音标失败', word)
            }
            if( !i.word_zh){
              if( ret.word_zh.length > 0){
                word_zh = ret.word_zh;
              }else{
                word_zh = '未知';
              }
            }
          }
          phonetic += '/';
          console.log('获取单词音标成功', i.word, phonetic, word_zh);
          let query = `update sys_allword set phonetic='${phonetic}'`;
          if( word_zh.length > 0){
            query += ` ,word_zh='${word_zh}'`;
          }
          query += ` where word='${i.word}'`;
          await querySql(query);
          bWait = true;
        }
      }catch(err){
        console.log(err);
      }
      if(bWait){
        await waitFor(3000);
        count++;
        if( count >= 12){
          break;
        }
      }
    }
  }
}

// 查询所有打卡记录列表
async function getStudyLogList(req, res, next) {
  const err = validationResult(req);
  // 如果验证错误，empty不为空
  if (!err.isEmpty()) {
    // 获取错误信息
    const [{ msg }] = err.errors;
    // 抛出错误，交给我们自定义的统一异常处理程序进行错误返回 
    next(boom.badRequest(msg));
  } else {

    let { pageSize, pageNo, params } = req.body;
    //console.log(params)
    // 默认值
    pageSize = pageSize ? pageSize : 1;
    pageNo = pageNo ? pageNo : 1;

    let query = 'select sys_studyword.id, words, nickname, book_id, sys_studyword.gmt_create from sys_studyword,sys_user'
    query += ' where sys_studyword.user_id=sys_user.id'
    if( params){
      if( params.book_id){
        query += ' and sys_studyword.book_id=' + params.book_id;
      }
      if( params.nickname){
        query += ' and sys_user.nickname like "%' + params.nickname + '%"';
      }
      if( params.user_id){
        query += ' and sys_studyword.user_id=' + params.user_id;
      }
    }
    try{
      let data = await querySql(query)
    	// console.log('任务列表查询===', data);
      if (!data || data.length === 0) {
        res.json({ 
        	code: CODE_SUCCESS, 
        	msg: '暂无数据', 
        	data: null 
        })
      } else {
        // 计算数据总条数
        let logIds = [];
        for( let i of data){
          logIds.push(i.id);
        }
        query = `select study_id,gmt_create,master_id,no_count from sys_studylog where study_id in (${ logIds.join(',') })`;
        if( params){
          if( params.gmt_create){
            if( params.gmt_create.length > 0 && params.gmt_create[0]){
              query += ' and gmt_create >=\'' + params.gmt_create[0] + '\'';
              if( params.gmt_create.length > 1&& params.gmt_create[1]){
                query += ' and gmt_create <=\'' + params.gmt_create[1] + '\'';
              }
            }
          }
          if( params.master_id >= 0){
            query += ' and master_id=' + params.master_id;
          }
        }
        let result_2 = await querySql(query)
        if (!result_2 || result_2.length === 0) {
          res.json({ 
            code: CODE_SUCCESS, 
            msg: '暂无数据', 
            data: null 
          })
        } else {
          // 计算数据总条数
          let total = result_2.length; 
          // 分页条件 (跳过多少条)
          let n = (pageNo - 1) * pageSize;
          // 拼接分页的sql语句命令
          query += ` order by gmt_create desc limit ${n} , ${pageSize}`;
          let result_3 = await querySql(query);
          res.json({ 
            code: CODE_SUCCESS, 
            msg: '查询数据成功', 
            data: {
              rows: result_3,
              total: total,
              pageNo: parseInt(pageNo),
              pageSize: parseInt(pageSize),
              studyWords: data.filter( item=>result_3.find(e=>e.study_id==item.id)),
            } 
          })
        }
      }
    }catch( err){
      console.log(err);
      res.json({ 
        code: CODE_ERROR, 
        msg: '暂无数据', 
        data: err 
      })
    }
  }
}

module.exports = {
  getWordList,
  addStudyWord,
  getStudyWordList,
  getStudyLogList,
  addStudyLog,
  getExamList,
  onTimerWordVoice
}
